﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKArch.Utils;

namespace YJKArch.AxisModule
{
	public class GridsTrimOperator
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public GridsTrimOperator(ExternalCommandData cmdData)
		{
			this.m_cmdData = cmdData;
			this.m_doc = cmdData.Application.ActiveUIDocument.Document;
			if (GridsTrimOperator._hWndRevit == null)
			{
				GridsTrimOperator._hWndRevit = new WindowHandle(Process.GetCurrentProcess().MainWindowHandle);
			}
			this.m_dlg = new GridsTrimForm(cmdData);
			this.m_dlg.Show(GridsTrimOperator._hWndRevit);
			int wMsg = 7;
			GridsTrimOperator.SendMessage(GridsTrimOperator._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
		}

		public Result Excute(ref string message)
		{
			Result result;
			try
			{
                if (-1 == (int)this.SelectGrid())
				{
					throw new System.ArgumentNullException();
				}
                if (-1 == (int)this.DoTrim())
				{
					throw new Exception("轴线剪裁失败！");
				}
				if (this.m_dlg.IsDeleteRefLine)
				{
					this.m_doc.Delete(this.m_selElement.Id);
				}
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception ex)
			{
				this.m_dlg.Close();
				message = ex.Message;
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private Result SelectGrid()
		{
			Selection selection = this.m_cmdData.Application.ActiveUIDocument.Selection;
			RevitVersionFuncs.ClearSelection(selection);
			Result result;
			try
			{
				SingleLineFilter singleLineFilter = new SingleLineFilter();
				Reference reference = selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, singleLineFilter, "请选择一根直线轴线、直线详图线或参照平面作为剪裁参考线");
				this.m_ptDir = selection.PickPoint("请点取一点以确定轴网剪裁的方向");
				this.m_selElement = this.m_doc.GetElement(reference);
				Grid grid =  this.m_selElement as Grid;
				if (grid != null)
				{
					this.m_selCurve = grid.Curve;
				}
				DetailLine detailLine = this.m_selElement as DetailLine;
				if (detailLine != null)
				{
					this.m_selCurve = detailLine.GeometryCurve;
				}
				ReferencePlane referencePlane = this.m_selElement as ReferencePlane;
				if (referencePlane != null)
				{
					XYZ startPoint = new XYZ(referencePlane.BubbleEnd.X, referencePlane.BubbleEnd.Y, 0.0);
					XYZ endPoint = new XYZ(referencePlane.FreeEnd.X, referencePlane.FreeEnd.Y, 0.0);
					this.m_selCurve = YJKLineEx.YJKGetBound(startPoint, endPoint);
				}
				XYZ closestPointTo = CurveAssistFunc.GetClosestPointTo(this.m_cmdData.Application, this.m_selCurve, this.m_ptDir, true);
				XYZ xyz = (this.m_ptDir - closestPointTo).Normalize();
				this.m_ptDir = closestPointTo + xyz * 1000.0;
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception)
			{
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private List<ElementId> GetGrids()
		{
			List<ElementId> list = new List<ElementId>();
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_cmdData.Application.ActiveUIDocument.Document).OfCategory(BuiltInCategory.OST_GridChains).OfClass(typeof(MultiSegmentGrid));
			List<ElementId> list2 = filteredElementCollector.ToElementIds().ToList<ElementId>();
			FilteredElementCollector filteredElementCollector2 = new FilteredElementCollector(this.m_cmdData.Application.ActiveUIDocument.Document).OfCategory(BuiltInCategory.OST_Grids).OfClass(typeof(Grid));
			foreach (ElementId elementId in filteredElementCollector.ToElementIds())
			{
				MultiSegmentGrid multiSegmentGrid = this.m_cmdData.Application.ActiveUIDocument.Document.GetElement(elementId) as MultiSegmentGrid;
				if (multiSegmentGrid != null)
				{
					list.Add(elementId);
				}
			}
			foreach (ElementId item in filteredElementCollector2.ToElementIds())
			{
				bool flag = false;
				foreach (ElementId elementId2 in list2)
				{
					if ((this.m_cmdData.Application.ActiveUIDocument.Document.GetElement(elementId2) as MultiSegmentGrid).GetGridIds().Contains(item))
					{
						flag = true;
					}
				}
				if (!flag)
				{
					list.Add(item);
				}
			}
			return list;
		}

		private void GetAllDimensionPacker()
		{
			new List<ElementId>();
			foreach (ElementId elementId in new FilteredElementCollector(this.m_cmdData.Application.ActiveUIDocument.Document).OfCategory(BuiltInCategory.OST_Dimensions).ToElementIds().ToList<ElementId>())
			{
				Element element = this.m_cmdData.Application.ActiveUIDocument.Document.GetElement(elementId);
				this.m_lstAllDimensionPacker.Add(new DimensionPacker(element as Dimension));
			}
		}

		private Result DoTrim()
		{
			try
			{
				this.GetAllDimensionPacker();
				List<Curve> list = new List<Curve>();
				list.Add(this.m_selCurve);
				foreach (ElementId elementId in this.GetGrids())
				{
					if (elementId.IntegerValue != this.m_selElement.Id.IntegerValue)
					{
						string name = "";
						ElementId elementId2 = null;
						List<Curve> list2 = new List<Curve>();
						MultiSegmentGrid multiSegmentGrid = this.m_doc.GetElement(elementId) as MultiSegmentGrid;
						if (multiSegmentGrid != null)
						{
							if (multiSegmentGrid.GetGridIds().Contains(this.m_selElement.Id))
							{
								continue;
							}
							list2 = this.TransformCurvesByGrid(multiSegmentGrid);
							name = multiSegmentGrid.Name;
							elementId2 = multiSegmentGrid.GetTypeId();
						}
						Grid grid =  this.m_doc.GetElement(elementId) as Grid;
						if (grid != null)
						{
							list2 = this.TransformCurvesByGrid(grid);
							name = grid.Name;
							elementId2 = grid.GetTypeId();
						}
						XYZ intersectPoint = this.GetIntersectPoint(list, list2);
						if (intersectPoint != null)
						{
							List<Curve> ar = new List<Curve>();
							List<Curve> ar2 = new List<Curve>();
							this.SplitListByPoint(list2, intersectPoint, ref ar, ref ar2);
							List<Curve> curveListByPoint = this.GetCurveListByPoint(ar, ar2, this.m_ptDir);
							if (curveListByPoint.Count == 1)
							{
								Line line = curveListByPoint.ElementAt(0) as Line;
								Arc arc = curveListByPoint.ElementAt(0) as Arc;
								Grid grid2 = null;
								if (line != null)
								{
									grid2 = this.m_cmdData.Application.ActiveUIDocument.Document.YjkNewGrid(line);
								}
								if (arc != null)
								{
									grid2 = this.m_cmdData.Application.ActiveUIDocument.Document.YjkNewGrid(arc);
								}
								this.m_cmdData.Application.ActiveUIDocument.Document.Regenerate();
								if (grid2 != null)
								{
									grid2.ChangeTypeId(elementId2);
									foreach (DimensionPacker dimensionPacker in this.m_lstAllDimensionPacker)
									{
										dimensionPacker.TryReplaceOneId(elementId.IntegerValue, new Reference(grid2));
									}
									this.m_cmdData.Application.ActiveUIDocument.Document.Delete(elementId);
									grid2.Name = name;
									grid2.HyExtendToAllLevels();
								}
							}
							else if (curveListByPoint.Count > 1)
							{
								Autodesk.Revit.DB.Document document = this.m_cmdData.Application.ActiveUIDocument.Document;
								CurveLoop conCurvesLoop = AxisAssistFunc.GetConCurvesLoop(this.m_cmdData.Application, curveListByPoint);
								Plane plane = RevitVersionFuncs.CreatePlanByNormalAndOrigin(XYZ.BasisZ, intersectPoint);
								ElementId id = SketchPlane.Create(this.m_cmdData.Application.ActiveUIDocument.Document, plane).Id;
								ElementId elementId3 = RevitDocumentExtension.CreateMultiSegmentGrid(document, elementId2, conCurvesLoop, id);
								Element element = document.GetElement(elementId3);
								this.m_cmdData.Application.ActiveUIDocument.Document.Regenerate();
								foreach (DimensionPacker dimensionPacker2 in this.m_lstAllDimensionPacker)
								{
									dimensionPacker2.TryReplaceOneId(elementId.IntegerValue, new Reference(element));
								}
								this.m_cmdData.Application.ActiveUIDocument.Document.Delete(elementId);
								element.Name = name;
							}
							this.m_cmdData.Application.ActiveUIDocument.Document.Regenerate();
						}
					}
				}
				foreach (DimensionPacker dimensionPacker3 in this.m_lstAllDimensionPacker)
				{
					if (dimensionPacker3.IfHasChanged)
					{
						dimensionPacker3.TryMakeNewDimension();
					}
				}
			}
			catch (Exception ex)
			{
				string message = ex.Message;
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private List<Curve> TransformCurvesByGrid(Element ele)
		{
			List<Curve> list = new List<Curve>();
			if (ele.GetType() == typeof(MultiSegmentGrid))
			{
				MultiSegmentGrid grid = ele as MultiSegmentGrid;
				list = AxisAssistFunc.GetLocationCurves(this.m_cmdData.Application, this.m_cmdData.Application.ActiveUIDocument.Document, grid);
			}
			else if (ele.GetType() == typeof(Grid))
			{
				Grid grid2 = ele as Grid;
				list.Add(grid2.Curve);
			}
			return list;
		}

		private XYZ GetIntersectPoint(List<Curve> arCurvesPri, List<Curve> arCurvesSec)
		{
			XYZ xyz = null;
			IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
			foreach (Curve curve in arCurvesPri)
			{
				foreach (Curve curve2 in arCurvesSec)
				{
					SetComparisonResult setComparisonResult = curve.Intersect(curve2, out intersectionResultArray);
					if (4 != (int)setComparisonResult && intersectionResultArray != null && !intersectionResultArray.IsEmpty)
					{
						xyz = intersectionResultArray.get_Item(0).XYZPoint;
						if (xyz != null)
						{
							return xyz;
						}
					}
				}
			}
			return xyz;
		}

		private Result SplitListByPoint(List<Curve> arCurves, XYZ point, ref List<Curve> ar1, ref List<Curve> ar2)
		{
			int num = 0;
			IntersectionResult intersectionResult = new IntersectionResult();
			foreach (Curve curve in arCurves)
			{
				intersectionResult = curve.Project(point);
				if (intersectionResult != null && intersectionResult.XYZPoint != null && point.IsAlmostEqualTo(intersectionResult.XYZPoint))
				{
					XYZ endPoint = curve.GetEndPoint(0);
					XYZ endPoint2 = curve.GetEndPoint(1);
					if (curve.GetType() == typeof(Line))
					{
						if (!point.IsAlmostEqualTo(endPoint))
						{
							ar1.Add(Line.CreateBound(endPoint, point));
						}
						if (!point.IsAlmostEqualTo(endPoint2))
						{
							ar2.Add(Line.CreateBound(point, endPoint2));
						}
					}
					else if (curve.GetType() == typeof(Arc))
					{
						Arc arc = curve as Arc;
						XYZ center = arc.Center;
						XYZ normal = arc.Normal;
						XYZ xyz = Geometry.CalculatMidPoint(endPoint, point, center, normal);
						XYZ xyz2 = Geometry.CalculatMidPoint(point, endPoint2, center, normal);
						if (!endPoint.IsAlmostEqualTo(point))
						{
							Arc item = Arc.Create(endPoint, point, xyz);
							ar1.Add(item);
						}
						if (!endPoint2.IsAlmostEqualTo(point))
						{
							Arc item2 = Arc.Create(point, endPoint2, xyz2);
							ar2.Add(item2);
						}
					}
					num++;
				}
				else if (num == 0)
				{
					ar1.Add(curve);
				}
				else
				{
					ar2.Add(curve);
				}
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private List<Curve> GetCurveListByPoint(List<Curve> ar1, List<Curve> ar2, XYZ point)
		{
			if (ar1.Count == 0)
			{
				return ar2;
			}
			if (ar2.Count == 0)
			{
				return ar1;
			}
			XYZ xyz = new XYZ(point.X, point.Y, 0.0);
			new IntersectionResult();
			double num = ar1[0].Distance(xyz);
			double num2 = ar2[0].Distance(xyz);
			foreach (Curve curve in ar1)
			{
				double num3 = curve.Distance(xyz);
				if (num3 < num)
				{
					num = num3;
				}
			}
			foreach (Curve curve2 in ar2)
			{
				double num4 = curve2.Distance(xyz);
				if (num4 < num2)
				{
					num2 = num4;
				}
			}
			if (num < num2)
			{
				return ar2;
			}
			return ar1;
		}

		protected ExternalCommandData m_cmdData;

		protected Document m_doc;

		private Element m_selElement;

		private Curve m_selCurve;

		private XYZ m_ptDir;

		private GridsTrimForm m_dlg;

		public static WindowHandle _hWndRevit;

		private List<DimensionPacker> m_lstAllDimensionPacker = new List<DimensionPacker>();
	}
}
